package com.junxonline.instant.admin.config;

import com.junxonline.instant.admin.shiro.AdminRealm;
import com.junxonline.instant.admin.shiro.AuthFilter;
import org.apache.shiro.mgt.DefaultSessionStorageEvaluator;
import org.apache.shiro.mgt.DefaultSubjectDAO;
import org.apache.shiro.mgt.SecurityManager;
import org.apache.shiro.spring.LifecycleBeanPostProcessor;
import org.apache.shiro.spring.security.interceptor.AuthorizationAttributeSourceAdvisor;
import org.apache.shiro.spring.web.ShiroFilterFactoryBean;
import org.apache.shiro.web.mgt.DefaultWebSecurityManager;
import org.springframework.aop.framework.autoproxy.DefaultAdvisorAutoProxyCreator;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.DependsOn;

import javax.servlet.Filter;
import java.util.LinkedHashMap;
import java.util.Map;

/**
 * Shiro配置类
 *
 * @author JunX
 * @date 2021-06-27
 */
@Configuration
public class ShiroConfig {

    /**
     * 无需登录认证
     */
    private static final String NOT_AUTH_KEY = "anon";

    /**
     * 需要登录认证
     */
    private static final String AUTH_KEY = "jwt";

    /**
     * shiro过滤器配置
     *
     * @param securityManager securityManager
     * @return ShiroFilterFactoryBean
     */
    @Bean("shiroFilter")
    public ShiroFilterFactoryBean shiroFilterFactoryBean(SecurityManager securityManager) {
        ShiroFilterFactoryBean shiroFilterFactoryBean = new ShiroFilterFactoryBean();
        Map<String, Filter> filterMap = new LinkedHashMap<>();
        // *要保证securityManager比自定义Filter先设置*
        shiroFilterFactoryBean.setSecurityManager(securityManager);
        filterMap.put(AUTH_KEY, new AuthFilter());
        shiroFilterFactoryBean.setFilters(filterMap);
        // 过滤链规则集合（有序）
        Map<String, String> filterRuleMap = new LinkedHashMap<>();
        // 无需认证的接口
        filterRuleMap.put("/login", NOT_AUTH_KEY);
        // 需要登录认证的接口
        filterRuleMap.put("/logout", AUTH_KEY);
        filterRuleMap.put("/getRouters", AUTH_KEY);
        filterRuleMap.put("/**/**", AUTH_KEY);
        filterRuleMap.put("/**", AUTH_KEY);
        shiroFilterFactoryBean.setFilterChainDefinitionMap(filterRuleMap);
        return shiroFilterFactoryBean;
    }

    /**
     * 安全管理器配置
     *
     * @param adminRealm adminRealm
     * @return SecurityManager
     */
    @Bean("securityManager")
    public SecurityManager securityManager(AdminRealm adminRealm) {
        // 设置自定义Realm
        DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager();
        securityManager.setRealm(adminRealm);
        // 关闭shiro自带的session
        DefaultSubjectDAO subjectDAO = new DefaultSubjectDAO();
        DefaultSessionStorageEvaluator defaultSessionStorageEvaluator = new DefaultSessionStorageEvaluator();
        defaultSessionStorageEvaluator.setSessionStorageEnabled(false);
        subjectDAO.setSessionStorageEvaluator(defaultSessionStorageEvaluator);
        securityManager.setSubjectDAO(subjectDAO);
        return securityManager;
    }

    /**
     * Spring整合Shiro
     *
     * @return LifecycleBeanPostProcessor
     */
    @Bean
    public static LifecycleBeanPostProcessor lifecycleBeanPostProcessor() {
        return new LifecycleBeanPostProcessor();
    }

    /**
     * 开启注解支持
     *
     * @return DefaultAdvisorAutoProxyCreator
     */
    @Bean
    @DependsOn("lifecycleBeanPostProcessor")
    public DefaultAdvisorAutoProxyCreator advisorAutoProxyCreator() {
        DefaultAdvisorAutoProxyCreator advisorAutoProxyCreator = new DefaultAdvisorAutoProxyCreator();
        advisorAutoProxyCreator.setProxyTargetClass(true);
        // 解决重复代理问题
        advisorAutoProxyCreator.setUsePrefix(true);
        // 添加前缀判断不匹配
        advisorAutoProxyCreator.setAdvisorBeanNamePrefix("_no_advisor");
        return advisorAutoProxyCreator;
    }

    /**
     * 开启注解支持
     *
     * @param securityManager 认证管理器
     * @return AuthorizationAttributeSourceAdvisor
     */
    @Bean
    public AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor(SecurityManager securityManager) {
        AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor = new AuthorizationAttributeSourceAdvisor();
        authorizationAttributeSourceAdvisor.setSecurityManager(securityManager);
        return authorizationAttributeSourceAdvisor;
    }

}
